import os
import platform
import sys

from PySide6.QtCore import Qt, Slot, QRect, QPropertyAnimation
from PySide6.QtGui import QPainter, QColor, QCursor
from PySide6.QtWidgets import QMainWindow, QTextBrowser

from utils.config import Settings
from utils.log import logger

script_path = os.path.abspath(os.path.dirname(sys.argv[0]))


# 创建窗口
class MainWindow(QMainWindow):

    def __init__(self, app, *args, **kwargs):
        super().__init__()

        self.app = app
        self.settings = Settings()

        # 窗体设置
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)  # 设置窗体无边框，且始终显示在最前
        self.setAttribute(Qt.WA_TranslucentBackground)  # 设置窗体背景透明

        # 文本框
        self.trans_text = QTextBrowser(self)
        self.trans_text.setAlignment(Qt.AlignCenter)  # 将文本框放置在窗口中央
        self.trans_text.setUpdatesEnabled(True)  # 启用文本框的重绘

        # 字体
        self.set_font_family_handler(self.settings.font_family)
        self.set_font_size_handler(self.settings.font_size)
        self.set_font_color_handler(self.settings.font_color)

        self.set_pos_handler(self.settings.pos)

        self.shrink_geo = QPropertyAnimation(self, b'geometry')
        self.expand_geo = QPropertyAnimation(self, b'geometry')
        self.is_shrink = False

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)  # 抗锯齿

        # # 光标进入窗体则取消透明
        # if self.rect().contains(self.mapFromGlobal(QtGui.QCursor.pos())):
        #     painter.setBrush(QColor(255, 255, 255, 255))
        # else:
        #     painter.setBrush(QColor(200, 200, 200, 200))

        painter.setBrush(QColor(200, 200, 200, self.settings.opacity))
        painter.drawRoundedRect(self.rect(), self.settings.margin, self.settings.margin)

    def enterEvent(self, event):
        # 鼠标进入窗口时显示手形光标
        self.setCursor(QCursor(Qt.PointingHandCursor))

        # if self.settings.enable_anim:
        #     self.expand(self.settings.pos)

        self.update()

    def leaveEvent(self, event):
        # 鼠标离开窗口时恢复为默认光标
        self.setCursor(QCursor(Qt.ArrowCursor))

        # if self.settings.enable_anim:
        #     self.shrink(self.settings.pos)

        self.update()

    def mousePressEvent(self, event):
        self.offset = event.position()

    def mouseMoveEvent(self, event):
        x, y = (event.globalPosition().toPoint().x() - self.offset.x(),
                event.globalPosition().toPoint().y() - self.offset.y())

        if x < 20:
            x = 0
        if x + self.width() + 20 > self.get_remain_rect().width():
            x = self.get_remain_rect().width() - self.width()
        if y < 20:
            y = 0
        if y + self.height() + 20 > self.get_remain_rect().height():
            y = self.get_remain_rect().height() - self.height()
        if abs(x + self.width() / 2 - self.get_remain_rect().width() / 2) < 10:
            x = int((self.get_remain_rect().width() - self.width()) / 2)
        if abs(y + self.height() / 2 - self.get_remain_rect().height() / 2) < 10:
            y = int((self.get_remain_rect().height() - self.height()) / 2)

        self.move(x, y)

    def mouseReleaseEvent(self, event):
        self.offset = None

    def resizeEvent(self, event):
        self.trans_text.setGeometry(
            self.settings.margin,
            self.settings.margin,
            self.width() - 2 * self.settings.margin,
            self.height() - 2 * self.settings.margin
        )

    def contextMenuEvent(self, event):
        self.app.menu.exec(event.globalPos())

    def get_remain_rect(self):
        # 获取屏幕大小
        screen_rect: QRect = self.app.primaryScreen().geometry()
        # 剩余屏幕空间初始化为屏幕大小
        remain_rect = QRect(screen_rect)

        if platform.system() == 'Windows':
            from utils.capi import get_taskbar_rect
            # 获取 Windows 任务栏大小
            taskbar_rect: QRect = get_taskbar_rect()

            if taskbar_rect.top() != screen_rect.top():
                remain_rect.setBottom(taskbar_rect.top())
            elif taskbar_rect.bottom() != screen_rect.bottom():
                remain_rect.setTop(taskbar_rect.bottom())
            elif taskbar_rect.left() != screen_rect.left():
                remain_rect.setRight(taskbar_rect.left())
            elif taskbar_rect.right() != screen_rect.right():
                remain_rect.setLeft(taskbar_rect.right())
            else:
                logger.warning('Cannot find the taskbar!')

        elif platform.system() == 'Linux':
            # Ubuntu 获取的屏幕大小本身就不包括 Dock，不需要做任何处理
            pass

        else:
            pass

        x, y, w, h = remain_rect.x(), remain_rect.y(), remain_rect.width(), remain_rect.height()
        logger.debug(f'Return remain rect, x={x}, y={y}, w={w}, h={h}')
        return remain_rect

    def get_expand_geo(self, pos):
        remain_rect = self.get_remain_rect()
        x, y, w, h = remain_rect.x(), remain_rect.y(), remain_rect.width(), remain_rect.height()

        if pos == 'down':
            w = int(remain_rect.width() / 2)
            h = int(remain_rect.height() / 5)
            x = int((remain_rect.width() - w) / 2)
            y = int(remain_rect.height() - h)

        elif pos == 'right':
            w = int(remain_rect.width() / 8)
            h = int(remain_rect.height() / 2)
            x = int(remain_rect.width() - w)
            y = int((remain_rect.height() - h) / 2)

        elif pos == 'up':
            w = int(remain_rect.width() / 2)
            h = int(remain_rect.height() / 5)
            x = int((remain_rect.width() - w) / 2)
            y = 0

        elif pos == 'left':
            w = int(remain_rect.width() / 8)
            h = int(remain_rect.height() / 2)
            x = 0
            y = int((remain_rect.height() - h) / 2)

        else:
            logger.exception(f'Position is undefined, pos={pos}')

        logger.debug(f'Return expand geometry, x={x}, y={y}, w={w}, h={h}')
        return QRect(x, y, w, h)

    def get_shrink_geo(self, pos):
        remain_rect = self.get_remain_rect()
        x, y, w, h = remain_rect.x(), remain_rect.y(), remain_rect.width(), remain_rect.height()

        if pos == 'down':
            w = int(remain_rect.width() / 2)
            h = self.settings.margin
            x = int((remain_rect.width() - w) / 2)
            y = int(remain_rect.height() - h)

        elif pos == 'right':
            w = self.settings.margin
            h = int(remain_rect.height() / 2)
            x = int(remain_rect.width() - w)
            y = int((remain_rect.height() - h) / 2)

        elif pos == 'up':
            w = int(remain_rect.width() / 2)
            h = self.settings.margin
            x = int((remain_rect.width() - w) / 2)
            y = 0

        elif pos == 'left':
            w = self.settings.margin
            h = int(remain_rect.height() / 2)
            x = 0
            y = int((remain_rect.height() - h) / 2)

        else:
            logger.exception(f'Position is undefined, pos={pos}')

        logger.debug(f'Return shrink geometry, x={x}, y={y}, w={w}, h={h}')
        return QRect(x, y, w, h)

    # 即将废弃
    @Slot()
    def set_show_hide_handler(self):
        if platform.system() == 'Windows':
            if self.isMinimized():
                self.showNormal()
                logger.debug('Show normal')
            else:
                self.showMinimized()
                logger.debug('Show minimized')

        elif platform.system() == 'Linux':
            if self.isVisible():
                self.setVisible(False)
                logger.debug('Show minimized')
            else:
                self.setVisible(True)
                logger.debug('Show normal')

        else:
            logger.warning(f'Current system: {platform.system()}')

    @Slot(str)
    def set_pos_handler(self, pos):
        logger.debug(f'Handle set_pos, pos={pos}')

        geometry = self.get_expand_geo(pos)
        self.setGeometry(geometry)
        self.trans_text.setGeometry(
            self.settings.margin,
            self.settings.margin,
            self.width() - 2 * self.settings.margin,
            self.height() - 2 * self.settings.margin
        )

    @Slot(str, int, str)
    def set_font_handler(self, font_family, font_size, font_color):
        logger.debug(f'Handle set_font, font_family={font_family}, font_size={font_size}, font_color={font_color}')

        self.trans_text.setStyleSheet(
            f'background-color: rgba(255, 255, 255, 0); '
            f'border: none; '
            f'font-family: {font_family}; '
            f'font-size: {font_size}px; '
            f'color: {font_color}'
        )

    @Slot(str)
    def set_font_family_handler(self, font_family):
        logger.debug(f'Handle set_font_family, font_family={font_family}')
        self.set_font_handler(font_family, self.settings.font_size, self.settings.font_color)

    @Slot(int)
    def set_font_size_handler(self, font_size):
        logger.debug(f'Handle set_font_size, font_size={font_size}')
        self.set_font_handler(self.settings.font_family, font_size, self.settings.font_color)

    @Slot(str)
    def set_font_color_handler(self, font_color):
        logger.debug(f'Handle set_font_color, font_color={font_color}')
        self.set_font_handler(self.settings.font_family, self.settings.font_size, font_color)

    @Slot(int)
    def set_opacity_handler(self, opacity):
        logger.debug(f'Handle set_opacity, opacity={opacity}')
        self.setWindowOpacity(opacity)
        self.update()

    @Slot(str)
    def set_trans_clipboard_handler(self, text):
        logger.debug(f'Handle set_trans_clipboard, text={text}')
        self.trans_text.setText(text)

    @Slot(str)
    def set_shrink_expand_handler(self, pos):
        logger.debug(f'Handle set_shrink_expand, pos={pos}')
        if self.is_shrink:
            self.expand(pos)
        else:
            self.shrink(pos)
        self.is_shrink ^= True

    def shrink(self, pos):
        self.shrink_geo.setDuration(self.settings.duration)

        self.shrink_geo.setStartValue(self.geometry())
        shrink_geometry = self.get_shrink_geo(pos)
        self.shrink_geo.setEndValue(shrink_geometry)

        self.shrink_geo.start()
        self.update()

        logger.debug('Return')

    def expand(self, pos):
        self.expand_geo.setDuration(self.settings.duration)

        self.expand_geo.setStartValue(self.geometry())
        expand_geometry = self.get_expand_geo(pos)
        self.expand_geo.setEndValue(expand_geometry)

        self.expand_geo.start()
        self.update()

        logger.debug('Return')
